#include "ProjectStateGlue.h"

#include "glue.h"
#include "GlueTypes.h"
#include "luna.h"

#include "Bridger.h"	// ProjectStateContext is *not* a Bridger subclass
						// but it will use the "C Helpers" macros
						// (which are not members of Bridger because
						// I am such a great programmer I wisely
						// kept them out for just these purposes ;-)

#include <stdarg.h>
#include <vector>

using namespace std;

class LuaProjectStateContext : ProjectStateContext
{
//	lua_State		*LL;
	vector<char *>	lines;
	unsigned int	current;

	void AddString(const char *ptr)
	{
		int len = strlen(ptr) + 1;
		char *sptr = new char[len];
		strncpy_s(sptr, len, ptr, _TRUNCATE);
		lines.push_back(sptr);
	}

	int GetString(char **handle)
	{
		if(current >= lines.size())
		{
			current = 0;
			*handle = NULL;
			return -1;
		}

		char *sptr = lines[current++];
		*handle = sptr;

		return strlen(sptr);	// this may be dumb!
	}

public:
	// NOW that I swapped the first two lines of Luna::constructor -
	// We have the nascent table {self} on the stack!
	LuaProjectStateContext(lua_State *L) : ProjectStateContext()
	{
//		LL = L;
		current = 0;
	}

	~LuaProjectStateContext()
	{
		for(unsigned int i = 0; i < lines.size(); i++)
		{
			delete lines[i];
		}
	}

  virtual void AddLine(const char *fmt, ...)
  {
	  va_list ap;
	  va_start(ap, fmt);

	  char *buf = challoc(BUFSIZ);
	  vsnprintf_s(buf, BUFSIZ, _TRUNCATE, fmt, ap);

	  AddString(buf);

	  free(buf);
	  va_end(ap);
  }

  virtual int GetLine(char *buf, int buflen)	// returns -1 on eof
  {
	  char *sptr = NULL;

	  if(buflen > 0)
	  {
		  buf[0] = NULL;
	  }

	  int len = GetString(&sptr);
	  if(len > 0)
	  {
		  strncpy_s(buf, buflen, sptr, _TRUNCATE);
	  }

	  return len;
  }

// now make a Luna templatized thingie!

// takes a ({self}, "line") returns void

	int fAddLine(lua_State *L)
	{
		const char *line = luaL_checkstring(L, 2);
		AddLine(line);
		return 0;
	}

// takes {self} returns string
	int fGetLine(lua_State *L)
	{
		char *buf = challoc(BUFSIZ);
		int len = GetLine(buf, BUFSIZ);
		lua_pushnumber(L, len);
		lua_pushstring(L, buf);
		free(buf);
		return 2;
	}

    static const char className[];
    static const Luna<LuaProjectStateContext>::RegType Register[];
};

const char LuaProjectStateContext::className[] = "ReaperProjectStateContext";
const Luna<LuaProjectStateContext>::RegType LuaProjectStateContext::Register[] = {
  { "AddLine", &LuaProjectStateContext::fAddLine },
  { "GetLine", &LuaProjectStateContext::fGetLine },
  { 0 }
};

ProjectStateContext * toProjectStateContext(lua_State *L, int idx)
{
#if 1
	return (ProjectStateContext *) toReaperObject(L, idx);
#else
	lua_pushnumber(L, 0);			// the userdata is stashed in element zero
	lua_gettable(L, idx);			// of this table
	ProjectStateContext **ctxh = (ProjectStateContext **)
								 lua_touserdata(L, -1);	//toProjectStateContext(L, 2);
	return *ctxh;
#endif
}


void setupProjectStateContext(lua_State *L)
{
	Luna<LuaProjectStateContext>::Register(L);	// userdata's metatable on stack
	lua_pop(L, 1);
}
